package helper

import (
	"net/url"
	"reflect"
	"strconv"
	"time"
)

// UrlValues2XormModel 将 url.Values 中对应的字段映射到 Xorm Model 上面
// 复杂类型的字段不支持
func UrlValues2XormModel(m url.Values, s interface{}) error {
	if m == nil || s == nil {
		return nil
	}

	t := reflect.TypeOf(s)
	if t.Kind() != reflect.Ptr {
		return LogError("映射 url.Values 到 xorm model 失败, model 必须为指针类型")
	}

	v := reflect.ValueOf(s).Elem()
	if v.Kind() != reflect.Struct {
		return LogError("映射 url.Values 到 xorm model 失败, model 必须为 struct 类型")
	}
	t = v.Type()

	// 遍历字段
	for i := 0; i < v.NumField(); i++ {
		fKey := t.Field(i).Name
		fVal := v.Field(i)
		mapVal := m.Get(fKey)

		switch fVal.Interface().(type) {
		case int:
			val, _ := strconv.Atoi(mapVal)
			v.Field(i).SetInt(int64(val))
		case string:
			v.Field(i).SetString(mapVal)
		case time.Time:
			if mapVal != "" {
				dt, err := time.Parse("2006-01-02 15:04:05", mapVal)
				if err != nil {
					return LogError("映射 url.Values 到 xorm model 失败, 不支持的 time 字段类型", err)
				}
				v.Field(i).Set(reflect.ValueOf(dt))
			}
		default:
			return LogError("映射 url.Values 到 xorm model 失败, 不支持的 model 字段类型")
		}
	}

	return nil
}

// Map2XormModel 将map中对应的字段映射到 Xorm Model 上面
// 复杂类型的字段不支持
func Map2XormModel(m map[string]interface{}, s interface{}) error {
	if m == nil || s == nil {
		return nil
	}

	t := reflect.TypeOf(s)
	if t.Kind() != reflect.Ptr {
		return LogError("映射map到 xorm model 失败, model 必须为指针类型")
	}

	v := reflect.ValueOf(s).Elem()
	if v.Kind() != reflect.Struct {
		return LogError("映射map到 xorm model 失败, model 必须为 struct 类型")
	}
	t = v.Type()

	// 遍历字段
	for i := 0; i < v.NumField(); i++ {
		fKey := t.Field(i).Name
		fVal := v.Field(i)

		switch fVal.Interface().(type) {
		case int:
			v.Field(i).SetInt(int64(getMapIntVal(m, fKey)))
		case string:
			v.Field(i).SetString(getMapStringVal(m, fKey))
		case time.Time:
			v.Field(i).Set(reflect.ValueOf(getMapTimeVal(m, fKey)))
		default:
			return LogError("映射 map 到 xorm model 失败, 不支持的 model 字段类型")
		}
	}

	return nil
}

// getMapStringVal 获取map string 字段值
func getMapStringVal(m map[string]interface{}, k string) string {
	if val, ok := m[k]; ok {
		switch t := val.(type) {
		case string:
			return t
		case int:
			return strconv.Itoa(t)
		case time.Time:
			return t.Format("2006-01-02 15:04:05")
		default:
			LogError("转换map值到string失败, 不支持的类型")
		}
	}

	return ""
}

// getMapIntVal 获取map int 字段值
func getMapIntVal(m map[string]interface{}, k string) int {
	if val, ok := m[k]; ok {
		switch t := val.(type) {
		case string:
			if v, err := strconv.Atoi(t); err != nil {
				LogError("转换map值到 int 失败, 不能转化到 int 的 string", err)
				return 0
			} else {
				return v
			}
		case int:
			return t
		// case time.Time:
		// 	return t.Format("2006-01-02 15:04:05")
		default:
			LogError("转换map值到 int 失败, 不支持的类型")
		}
	}

	return 0
}

// getMapTimeVal 获取map Time 字段值
func getMapTimeVal(m map[string]interface{}, k string) time.Time {
	if val, ok := m[k]; ok {
		switch t := val.(type) {
		case string:
			dt, err := time.Parse("2006-01-02 15:03:04", t)
			if err != nil {
				LogError("转换map值到 time 失败", err)
			}

			return dt
		case int:
			return time.Unix(int64(t), 0)
		case int64:
			return time.Unix(t, 0)
		case time.Time:
			return t
		default:
			LogError("转换map值到string失败, 不支持的类型")
		}
	}

	zero, _ := time.Parse("2006-01-02 15:03:04", "0001-01-01 00:00:00")
	return zero
}
